#pragma once

#include <map>
#include <list>
#include <vector>
#include <string>

#include "WeightedItem.h"
#include "NamedItem.h"

typedef enum NodeType_t
{
	NodeTypeUser = 0,
	NodeTypeItem = 1
} NodeType;

typedef NamedItem<std::string, NodeType> Node;
typedef WeightedItem<Node*, double> Edge;
typedef WeightedItem<std::string, double> Label;

typedef std::list<Edge*> ListEdge;
typedef std::vector<Label*> ListLabel;
typedef std::vector<double> ListNumber;

typedef std::map<Node*, ListEdge*> Graph;
typedef std::map<Node*, ListLabel*> LabelDistribution;
typedef std::map<Node*, ListNumber*> MapNumber;

class AdsorptionData
{
public:

	std::list<Node*> nodes;
	LabelDistribution labelDistributions;
	LabelDistribution finalLabelDistributions;

	Graph graphUsers;
	Graph graphItems;
	MapNumber probabilities;

	~AdsorptionData()
	{
		deleteMapWithVals<LabelDistribution, ListLabel>(labelDistributions);
		deleteMapWithVals<LabelDistribution, ListLabel>(finalLabelDistributions);
		deleteMapWithVals<Graph, ListEdge>(graphItems);
		deleteMapWithVals<Graph, ListEdge>(graphUsers);
		deleteMap<MapNumber, ListNumber>(probabilities);

		for (std::list<Node*>::iterator itNode(nodes.begin()), itNodeEnd(nodes.end());
			itNode != itNodeEnd; itNode++)
		{
			delete (*itNode);
		}
		nodes.clear();
	}

private:

	template<typename Container, typename Value>
	void deleteMapWithVals(Container &labDist)
	{
		Container::iterator itLabDist, itLabDistEnd;

		itLabDist = labDist.begin();
		itLabDistEnd = labDist.end();
		for (; itLabDist != itLabDistEnd; itLabDist++)
		{
			Value *lstLabels = itLabDist->second;

			for (Value::iterator itLabel(lstLabels->begin()), itLabelEnd(lstLabels->end());
				itLabel != itLabelEnd; itLabel++)
			{
				delete (*itLabel);
			}
			lstLabels->clear();
			delete lstLabels;
		}
		labDist.clear();
	}

	template<typename Container, typename Value>
	void deleteMap(Container &labDist)
	{
		Container::iterator itLabDist, itLabDistEnd;

		itLabDist = labDist.begin();
		itLabDistEnd = labDist.end();
		for (; itLabDist != itLabDistEnd; itLabDist++)
		{
			Value *lstLabels = itLabDist->second;
			lstLabels->clear();
			delete lstLabels;
		}
		labDist.clear();
	}
};